package tk.mynoteapp.dev.demo05.ribbonretry;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import tk.mynoteapp.dev.demo05.ribbonretry.feign.SmsClient;

import java.util.UUID;

/**
 * 你是否知道 Ribbon 会自动重试请求呢？
 *  一些 HTTP 客户端往往会内置一些重试策略，其初衷是好的，毕竟因为网络问题导致丢包虽然频繁但持续时间短，
 *  往往重试下第二次就能成功，但一定要小心这种自作主张是否符合我们的预期。
 *
 * Ribbon重试问题解决办法：
 *  一是，把发短信接口从 Get 改为 Post。其实，这里还有一个 API 设计问题，有状态的 API 接口不应该定义为 Get。
 *  根据 HTTP 协议的规范，Get 请求用于数据查询，而 Post 才是把数据提交到服务端用于修改或新增。选择 Get 还是
 *  Post 的依据，应该是 API 的行为，而不是参数大小。这里的一个误区是，Get 请求的参数包含在 Url QueryString
 *  中，会受浏览器长度限制，所以一些同学会选择使用 JSON 以 Post 提交大参数，使用 Get 提交小参数。
 *
 *  二是，将 MaxAutoRetriesNextServer 参数配置为 0，禁用服务调用失败后在下一个服务端节点的自动重试。在配置
 *  文件中添加一行即可：ribbon.MaxAutoRetriesNextServer=0
 *
 * 根本原因：
 *  1）Get 请求应该是无状态或者幂等的，短信接口可以设计为支持幂等调用的；
 *  2）而用户服务的开发同学，如果对 Ribbon 的重试机制有所了解的话，或许就能在排查问题上少走些弯路。
 */
@RestController
@RequestMapping("ribbonretryissueclient")
public class RibbonRetryIssueClientController {
    private Logger logger = LoggerFactory.getLogger(RibbonRetryIssueClientController.class);
//    @Autowired
    private SmsClient smsClient;

    @GetMapping("wrong")
    public String wrong() {
        logger.info("client is called");
        try {
            smsClient.sendSmsWrong("13600000000", UUID.randomUUID().toString());
        } catch (Exception ex) {
            logger.error("send sms failed : {}", ex.getMessage());
        }
        return "done";
    }

    @GetMapping("right")
    public String right() {
        logger.info("client is called");
        try {
            smsClient.sendSmsRight("13600000011", UUID.randomUUID().toString());
        } catch (Exception ex) {
            logger.error("send sms failed : {}", ex.getMessage());
        }
        return "done";
    }
}
